﻿using FastSocket.Client;
using FastSocket.SocketBase;
using SocketTool.Com.Args;
using SocketTool.Model.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace SocketTool.Com.TCP.Client
{
    public class TCPClient : SocketClient<TCPClientMessage>, ISocket
    {
        private TCPClientProtocol mProtocol { get; }

        private TCPClientDataModel mSocketModel { get; }

        public event EventHandler<ConnectionArgs> SocketConnectionChangedEvent;
        
        public event EventHandler<ReceiveMessageArgs> ReceiveMessageEvent;

        public TCPClient(TCPClientDataModel socket)
            : this(new TCPClientProtocol(),socket.SocketBufferSize,socket.MsgBufferSize,socket.SendTimeout,socket.ReceiveTimeout)
        {
            if (socket == null) throw new ArgumentNullException("socket");
            this.mSocketModel = socket;
        }

        public TCPClient(TCPClientProtocol protocol,
          int socketBufferSize,
          int messageBufferSize,
          int millisecondsSendTimeout,
          int millisecondsReceiveTimeout)
          : base(protocol, socketBufferSize, messageBufferSize, millisecondsSendTimeout, millisecondsReceiveTimeout)
        {
            if (protocol == null) throw new ArgumentNullException("protocol");
            this.mProtocol = protocol;
        }


        public void Close()
        {
            this.UnRegisterEndPoint(this.mSocketModel.Id);
        }

        public bool Open()
        {
            if (!this.TryRegisterEndPoint(this.mSocketModel.Id, new[] { new IPEndPoint(IPAddress.Parse(this.mSocketModel.ServerIP), this.mSocketModel.ServerPort) }))
            {
                return false;
            }
            return true;

        }

        public void Send(string msg, int count)
        {
            var bt = Encoding.UTF8.GetBytes(msg);
            var sendBt = this.mProtocol.Protocols.GetSendData(bt);
            for (int i = 0; i < count; i++)
            {
                this.Send(new Packet(sendBt));
            }
        }

        public void SetCustomerProtocol(CustomerProtocol protocol)
        {
            this.mProtocol.Protocols = protocol;
        }

        protected override void OnConnected(IConnection connection)
        {
            base.OnConnected(connection);
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("OnConnected");
            Console.ResetColor();
            this.SocketConnectionChangedEvent?.Invoke(this, new ConnectionArgs(connection));
        }

        protected override void OnDisconnected(IConnection connection, Exception ex)
        {
            base.OnDisconnected(connection, ex);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("OnDisconnected");
            Console.ResetColor();
            this.SocketConnectionChangedEvent?.Invoke(this, new ConnectionArgs(connection));
        }

        protected override void OnConnectionError(IConnection connection, Exception ex)
        {
            base.OnConnectionError(connection, ex);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("OnConnectionError");
            Console.ResetColor();
            this.SocketConnectionChangedEvent?.Invoke(this, new ConnectionArgs(connection));
        }

        protected override void OnMessageReceived(IConnection connection, MessageReceivedEventArgs e)
        {
            int readlength;
            TCPClientMessage message = null;
            try
            {
                message = this.mProtocol.Parse(connection, e.Buffer, out readlength);
            }
            catch (Exception ex)
            {
                base.OnConnectionError(connection, ex);
                connection.BeginDisconnect(ex);
                e.SetReadlength(e.Buffer.Count);
                return;
            }

            if (message != null)
            {
                string msg = Encoding.UTF8.GetString(message.Payload);
                this.ReceiveMessageEvent?.Invoke(this, new ReceiveMessageArgs(null,msg));
            }

            if (readlength > e.Buffer.Count)
                readlength = e.Buffer.Count;
            e.SetReadlength(readlength);
        }
    }
}
